import * as io from 'socket.io-client';
import { TPromise } from 'vs/base/common/winjs.base';
export class WebSocketMessage {
    public event: string;
    public result: any;
    public message: string;
    public success: boolean;
}
export function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
export class Hub {
    private static _search: Hub;
    static get search(): Hub {
        if (!Hub._search) {
            Hub._search = new Hub("search");
        }
        return Hub._search;
    }
    private static _typescript: Hub;
    static get typescript(): Hub {
        if (!Hub._typescript) {
            Hub._typescript = new Hub("typescript");
        }
        return Hub._typescript;
    }
    private static _extension: Hub;
    static get extension(): Hub {
        if (!Hub._extension) {
            Hub._extension = new Hub("extension");
        }
        return Hub._extension;
    }
    private static _editing: Hub;
    static get editing(): Hub {
        if (!Hub._editing) {
            Hub._editing = new Hub("editing");
        }
        return Hub._editing;
    }
    private static _fs: Hub;
    static get fs(): Hub {
        if (!Hub._fs) {
            Hub._fs = new Hub("fs");
        }
        return Hub._fs;
    }
    private static _vscode: Hub;
    static get vscode(): Hub {
        if (!Hub._vscode) {
            Hub._vscode = new Hub("vscode");
        }
        return Hub._vscode;
    }
    private static _encoding: Hub;
    static get encoding(): Hub {
        if (!Hub._encoding) {
            Hub._encoding = new Hub("encoding");
        }
        return Hub._encoding;
    }
    private static _server: Hub;
    static get server(): Hub {
        if (!Hub._server) {
            Hub._server = new Hub("server");
        }
        return Hub._server;
    }
    private static _hash: Hub;
    static get hash(): Hub {
        if (!Hub._hash) {
            Hub._hash = new Hub("hash");
        }
        return Hub._hash;
    }
    static async disconnect() {
        return new Promise((r) => {
            Hub.onclose = () => {
                delete Hub.webSocket;
                r();
            }
            Hub.webSocket.disconnect();
        });
    }
    static connect() {
        return Hub.initWebSocket().then(() => {
            console.log("连接成功，开始认证");
            Hub.webSocket.emit('authentication', { token: "John" });
        }).then(() => {
            return new TPromise((resolve) => {
                Hub.webSocket.on('authenticated', function () {
                    console.log("认证成功");
                    resolve(true);
                });
            });
        });
    }
    private static onclose: () => void;
    private static webSocket: SocketIOClient.Socket;
    private static webSocketIniting: boolean;
    private methodEvents: any = {};
    private serverEvents: any = {};
    private static hubs: any = {};
    constructor(private hub: string) {
        this.methodEvents = {};
        this.serverEvents = {};
        Hub.hubs[hub] = this;

        Hub.initWebSocket().then(() => {
            Hub.webSocket.on(this.hub, (data) => {
                var message = <WebSocketMessage>data;
                if (!message.success) {
                    var fn = this.methodEvents[message.event];
                    if (!fn) {
                        return;
                    }
                    fn.reject && fn.reject(message.result);
                    delete this.methodEvents[message.event];
                    return;
                }
                var fn = this.methodEvents[message.event];
                if (fn) {
                    fn.resolve && fn.resolve(message.result);
                }
                delete this.methodEvents[message.event];
                fn = this.serverEvents[message.event.toLocaleLowerCase()];
                if (fn) {
                    fn(message.result);
                }
            });
        });
    }

    private static initWebSocket(): TPromise<SocketIOClient.Socket> {
        return new TPromise<SocketIOClient.Socket>((resolve) => {
            if (Hub.webSocket) {
                resolve(Hub.webSocket);
                return;
            }
            if (Hub.webSocketIniting) {
                var wait = () => {
                    if (!Hub.webSocket) {
                        setTimeout(wait, 100);
                        return;
                    }
                    Hub.webSocketIniting = false;
                    resolve(Hub.webSocket);
                }
                wait();
                return;
            }
            Hub.webSocketIniting = true;
            var webSocket = io("http://server.vscode.codecity.online:8009/");
            webSocket.on("connect", () => {
                Hub.webSocket = webSocket;
                Hub.webSocketIniting = false;
                resolve(Hub.webSocket);
            });
            webSocket.on("connect_error", (e) => {
                console.log("error");
                console.dir(e);
            });
            webSocket.on("disconnect", (e) => {
                //if (e.reason == "1006") {
                //    webSocket = new WebSocket("ws://" + location.host + "/ws");
                //    Hub.webSocket = webSocket;
                //    return;
                //}
                Hub.onclose && Hub.onclose();
                Hub.onclose = null;
                Hub.webSocket = null;
            });
        });
    }

    public on(event: string, callback: (msg: any) => void) {
        this.serverEvents[event.toLocaleLowerCase()] = callback;
        return this;
    }

    public un(event: string) {
        delete this.serverEvents[event];
        return this;
    }

    public call<T>(method: string, ...args: any[]): TPromise<T> {
        return new TPromise<T>(async (resolve, reject) => {
            var uuid = guid();
            this.methodEvents["on" + method.toLowerCase() + uuid] = {
                resolve: resolve,
                reject: reject
            }
            await Hub.initWebSocket();
            Hub.webSocket.emit(this.hub, {
                method: method,
                id: uuid,
                args: args
            });
        });
    }
}
